#import "FoursquareLogin.h"

// Shared instance of FoursquareLogin
static FoursquareLogin* sharedFoursquareLogin = nil;

//  This Foursquare integration is possible thanks to the Foursquare API by
//  Eric Butler and associates.
//
//  Copyright (C) 2010 Eric Butler <eric@codebutler.com>
//
//  FoursquareLogin is created with much reference to Constantine Fry's sample
//  classes in the Foursquare API.
//
//  Created by Constantine Fry on 10/10/10.
//  Copyright 2010 Home. All rights reserved.

/**
 * A FoursquareLogin is a tool for logging in to the Foursquare system.
 *
 * Code used within this class and the supporting API was written by 
 * Eric Butler, Constantine Fry, and other associates.
 *
 * The supporting API can be found in ./FourSquareAPI folder.
 *
 * @author      Eric Butler
 * @author      Constantine Fry
 * @author      James Lin
 * @version     2.3.2 
 * @since       2.0.0
 */
@implementation FoursquareLogin

@synthesize isLoggedIn;

/**
 * Retrieve the shared instance of the Foursquare login.
 *
 * @return  the shared instance of FoursquareLogin
 */
+ (FoursquareLogin*)sharedFoursquareLogin {
	@synchronized(self) {
		if (sharedFoursquareLogin == nil) {
			sharedFoursquareLogin = [[FoursquareLogin alloc] init];
		}
		return sharedFoursquareLogin;
	}
}

/**
 * Allocate the Foursquare login.
 *
 * @return  the newly allocated shared instance of FoursquareLogin
 */
+ (id) alloc {
	@synchronized(self) {
		sharedFoursquareLogin = [super alloc];
		return sharedFoursquareLogin;
	}
}

/**
 * Retrieve a copy of the Foursquare login.
 *
 * @return  the shared instance of FoursquareLogin
 */
+ (id) copy {
	@synchronized(self) {
		return sharedFoursquareLogin;
	}
}

/**
 * Helper method to create the login form.
 */
- (void)createLoginForm {
	loginPopup = [[UIAlertView alloc] initWithTitle:@""
											message:@"\n\n\n\n\n" 
										   delegate:self 
								  cancelButtonTitle:nil
								  otherButtonTitles:nil];
	CGFloat xCenter = 284 / 2;
	
	// Create the Foursquare sign in image header (180 x 24)
	signInHeader = [[UIImageView alloc] initWithImage:
						   [UIImage imageNamed:FOURSQUARE_LOGIN_IMAGE]]; 
	[signInHeader setFrame:CGRectMake(xCenter-90, 13, 180, 24)];
	[loginPopup addSubview:signInHeader];
	
	// Create the powered by Foursquare image header (150 x 24)
	poweredByHeader = [[UIImageView alloc] initWithImage:
					[UIImage imageNamed:FOURSQUARE_REF_IMAGE]]; 
	[poweredByHeader setFrame:CGRectMake(xCenter-75, 13, 150, 24)];
	[loginPopup addSubview:poweredByHeader];
	
	// Create the text field for user identifier login
	userField = [[UITextField alloc]initWithFrame:CGRectMake(xCenter-100, 50, 
															 200, 30)];
	userField.keyboardType = UIKeyboardTypeEmailAddress;
	userField.keyboardAppearance = UIKeyboardAppearanceAlert;
	userField.autocapitalizationType = UITextAutocapitalizationTypeNone;
	userField.autocorrectionType = UITextAutocorrectionTypeNo;
	userField.delegate = self;
	userField.returnKeyType = UIReturnKeyNext;
	userField.placeholder = @"Email/Phone";
	userField.clearButtonMode = UITextFieldViewModeUnlessEditing;
	userField.borderStyle = UITextBorderStyleBezel;
	userField.backgroundColor = [UIColor whiteColor];
	[loginPopup addSubview:userField];
	
	// Create the text field for the user password login
	passwordField = [[UITextField alloc]initWithFrame:CGRectMake(xCenter-100, 80, 
																 200, 30)];
	passwordField.returnKeyType = UIReturnKeyDone;
	passwordField.keyboardAppearance = UIKeyboardAppearanceAlert;
	passwordField.autocapitalizationType = UITextAutocapitalizationTypeNone;
	passwordField.autocorrectionType = UITextAutocorrectionTypeNo;
	passwordField.delegate = self;
	passwordField.placeholder = @"Password";
	passwordField.secureTextEntry = YES;
	passwordField.clearButtonMode = UITextFieldViewModeUnlessEditing;
	passwordField.borderStyle = UITextBorderStyleBezel;
	passwordField.backgroundColor = [UIColor whiteColor];
	[loginPopup addSubview:passwordField];
	
	// Create a custom sign in button for the login pop-up
	signInButton = [UIButton buttonWithType:UIButtonTypeCustom];
	[signInButton addTarget:self 
					 action:@selector(attemptLogin)
		   forControlEvents:UIControlEventTouchUpInside];
	signInButton.frame = CGRectMake(xCenter-127, 130, 127, 43);
	[signInButton setBackgroundImage:[UIImage imageNamed:SIGNIN_BUTTON_IMAGE_FILENAME] 
							forState:UIControlStateNormal];
	//signInButton.center = CGPointMake(100, 120);
	[loginPopup addSubview:signInButton];
	
	cancelButton = [UIButton buttonWithType:UIButtonTypeCustom];
	[cancelButton addTarget:self 
					 action:@selector(dismissLogin)
		   forControlEvents:UIControlEventTouchUpInside];
	cancelButton.frame = CGRectMake(xCenter, 130, 127, 43);
	[cancelButton setBackgroundImage:[UIImage imageNamed:CANCEL_BUTTON_IMAGE_FILENAME] 
							forState:UIControlStateNormal];
	//signInButton.center = CGPointMake(100, 120);
	[loginPopup addSubview:cancelButton];
	
	
	loginStatusLabel = [[UILabel alloc] initWithFrame:CGRectMake(xCenter-100, 60, 
																 200, 60)];
	loginStatusLabel.backgroundColor = [UIColor clearColor];
	loginStatusLabel.font = [UIFont boldSystemFontOfSize:16.0];
	loginStatusLabel.textColor = [UIColor whiteColor];
	loginStatusLabel.textAlignment = UITextAlignmentCenter;
	loginStatusLabel.lineBreakMode = UILineBreakModeWordWrap;
	loginStatusLabel.numberOfLines = 0;
	[loginPopup addSubview:loginStatusLabel];
}

/**
 * Initialize the Foursquare login.
 *
 * @return  the initialized FoursquareLogin
 */
- (id)init {
    if ((self = [super initWithFrame:CGRectMake(0, 0, 180, 24)])) {
		// Create the login button
        loginButton = [UIButton buttonWithType:UIButtonTypeCustom];
		loginButton.frame = CGRectMake(0, 0, 180, 24);
		[loginButton setBackgroundImage:[UIImage imageNamed:FOURSQUARE_LOGIN_IMAGE] 
												   forState:UIControlStateNormal];
		[loginButton addTarget:self 
						action:@selector(showLogin)
			  forControlEvents:UIControlEventTouchUpInside];
		[self addSubview:loginButton];
		
		// Create the login popup
		[self createLoginForm];
		
		_isLoggedIn = NO;
    }
    return self;
}

/**
 * Display the login pop-up.
 *
 * @param theDelegate  the delegate handling login response
 */
- (void)showLoginWithDelegate:(id<FoursquareLoginDelegate>)theDelegate {
	delegate = theDelegate;
	[loginPopup show];
}

/**
 * Dismiss the login pop-up.
 */
- (void)dismissLogin {
	[userField resignFirstResponder];
	[passwordField resignFirstResponder];
	[loginPopup dismissWithClickedButtonIndex:0 animated:YES];
}

/**
 * Handle a call to attempt login.
 */
- (void)attemptLogin {
	[self loginWithUser:userField.text password:passwordField.text];
}

/**
 * Helper method to hide the login form.
 */
- (void)hideLoginForm {
	poweredByHeader.hidden = NO;
	loginStatusLabel.hidden = NO;
	signInHeader.hidden = YES;
	userField.hidden = YES;
	passwordField.hidden = YES;
	signInButton.hidden = YES;
	cancelButton.hidden = NO;
}

/**
 * Helper method to show the login form.
 */
- (void)showLoginForm {
	poweredByHeader.hidden = YES;
	loginStatusLabel.hidden = YES;
	signInHeader.hidden = NO;
	userField.hidden = NO;
	passwordField.hidden = NO;
	signInButton.hidden = NO;
	cancelButton.hidden = NO;
}

/**
 * Helper method to show that the login attempt is pending.
 */
- (void)showLoginIndicator {
	loginIndicator = [[UIActivityIndicatorView alloc] 
					  initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
	loginIndicator.center = CGPointMake(142, 60);
	[loginPopup addSubview:loginIndicator];
	
	[loginIndicator startAnimating];
}

/**
 * Helper method to show that the login attempt is finished.
 */
- (void)hideLoginIndicator {
	[loginIndicator stopAnimating];
	[loginIndicator release];
}

/**
 * Handle the call to a successful login attempt.
 */
- (void)loginComplete {
	_isLoggedIn = YES;
	
	NSString* msg = @"Signed in successfully.";
	[GraphicsUtilities displayAlertWithTitle:msg message:nil];
	
	// Clear the user info
	userField.text = @"";
	passwordField.text = @"";
	
	// Notify delegate
	if (delegate) {
		[delegate handleFoursquareLoginSuccess];
	}
	
	// Hide the keyboard
	[userField resignFirstResponder];
	[passwordField resignFirstResponder];
	
	// Hide the login pop-up
	[loginPopup dismissWithClickedButtonIndex:1 animated:YES];
}

/**
 * Login to the Foursquare system with given user account information.
 *
 * @param user      the account identifier of the user account
 * @param password  the password of the user account
 */
- (void)loginWithUser:(NSString*)user password:(NSString*)password {
	if ([user length] == 0 || [password length] == 0) {
		NSString* msg = @"Please enter your login information.";
		[GraphicsUtilities displayShiftedAlertWithTitle:msg
												message:nil 
											 horizShift:0 
											  vertShift:80];
		return;
	}
	
	[self hideLoginForm];
	[self showLoginIndicator];
	
	[Foursquare getOAuthAccessTokenForUsername:user password:password callback:
	 ^(BOOL success, id response) {
		 [self hideLoginIndicator];
		 [self showLoginForm];
		 
		 if (success) {
			 // Store the authentication data for this session
			 NSDictionary* dict = [response objectForKey:@"credentials"];
			 NSString* token  = [dict objectForKey:@"oauth_token"];
			 NSString* secret = [dict objectForKey:@"oauth_token_secret"];
			 
			 NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
			 [defaults setObject:token  forKey:FS_ACC_TOKEN];
			 [defaults setObject:secret forKey:FS_ACC_SECRET];
			 [defaults synchronize];
			 
			 [Foursquare setOAuthAccessToken:token secret:secret];
			 [self loginComplete];
		 } else {
			 [GraphicsUtilities displayShiftedAlertWithTitle:@"Invalid login credentials." 
													 message:nil 
												  horizShift:0 
												   vertShift:80];
		 }
	 }];
}

/**
 * Custom getter for checking whether the user is logged in.
 *
 * @return  whether the user is currently logged in
 */
- (BOOL)checkLoggedIn {
	[Foursquare detailForCurrentUser:NO showMayor:NO callback:
	 ^(BOOL success, id response) {
		 if (success) {
			 // Get the name of the authenticated user
			 NSDictionary* userDict = [response objectForKey:@"user"];
			 
			 NSString* firstName  = [userDict objectForKey:@"firstname"];
			 NSString* lastName = [userDict objectForKey:@"lastname"];
			 
			 firstName = firstName ? firstName : @"";
			 lastName = lastName ? lastName : @"";
			 
			 // Display user name on login status label
			 loginStatusLabel.text = [NSString stringWithFormat:@"Logged in as %@ %@.", 
			 						  firstName, lastName];
			 _isLoggedIn = YES;
		 } else {
			 // Not logged in
			 _isLoggedIn = NO;
		 }
	 }];
	
	return _isLoggedIn;
}

/**
 * Log out of the Foursquare system with currently authenticated user.
 */
- (void)logout {
	if (_isLoggedIn) {
		// Remove the authentication data for this session
		[Foursquare removeOAUthAccessTokenAndSecret];
		
		NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
		[defaults removeObjectForKey:FS_ACC_TOKEN];
		[defaults removeObjectForKey:FS_ACC_SECRET];
		[defaults synchronize];
		
		_isLoggedIn = NO;
		
		[GraphicsUtilities displayAlertWithTitle:@"Signed out successfully."
										 message:nil];
	}
}


/**
 * Manage the actions of the return key on the keyboard.
 *
 * @see  UITextFieldDelegate
 */
- (BOOL)textFieldShouldReturn:(UITextField*)textField {
	if (textField == userField) {
		[passwordField becomeFirstResponder];
	} else if (textField == passwordField) {
		[self attemptLogin];
	}
	return NO;
}

/**
 * Display the appropriate content of the login pop-up when it appears.
 *
 * @see  UIAlertViewDelegate
 */
- (void)didPresentAlertView:(UIAlertView*)alertView {
	[self checkLoggedIn];
	
	if (!_isLoggedIn) {
		[self showLoginForm];
		[userField becomeFirstResponder];
	} else {
		[self hideLoginForm];
	}
}

/**
 * Deallocate the Foursquare login.
 */
- (void)dealloc {
	delegate = nil;
	[poweredByHeader release], poweredByHeader = nil;
	[loginStatusLabel release], loginStatusLabel = nil;
	[signInHeader release], signInHeader = nil;
	[signInButton release], signInButton = nil;
	[cancelButton release], cancelButton = nil;
	[userField release], userField = nil;
	[passwordField release], passwordField = nil;
	[loginPopup release], loginPopup = nil;
	[loginButton release], loginButton = nil;
	[sharedFoursquareLogin release], sharedFoursquareLogin = nil;
    [super dealloc];
}

@end